﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace GameEngine
{
    public class AnimatedSprite : Sprite
    {
        //------------------- Getters & Setters

        // Is our sprite animating?
        // It's getter and setter too
        // If we're not animating and we have a specific stop frame, set it to the current frame
        public bool Animating
        {
            get { return animating; }
            set
            {
                animating = value;

                if (!animating && animations[current_animation].StopFrame != -1)
                    current_frame = animations[current_animation].StopFrame;
            }
        }
        bool animating = false;

        // Does our sprite animation repeat or not
        public bool Repeating
        {
            get { return repeating; }
            set { repeating = value; }
        }
        bool repeating = true;

        // The position our sprite is located at
        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }
        protected Vector2 position = Vector2.Zero;

        // Getter and setter for frames per second that it animates at
        public int FramesPerSecond
        {
            get { return (int)(1f / frame_time); }
            set { frame_time = (float)Math.Max(1f / (float)value, .001f); }
        }
        float frame_time = 0.5f;

        //------------------- Vars

        // The current frame in the animation
        int current_frame = 0;

        float timer = 0;

        // This holds 
        Dictionary<string, Animation> animations = new Dictionary<string, Animation>();
        string current_animation = null;

        //------------------- Constructs

        public AnimatedSprite(Texture2D texture, int tile_width, int tile_height, bool animating = false, int sheet_width = 0, int sheet_height = 0)
            : base(texture, tile_width, tile_height, sheet_width = 0, sheet_height = 0)
        {
            this.animating = animating;
        }

        public AnimatedSprite(ContentManager Content, string filename, int tile_width, int tile_height, bool animating, int sheet_width = 0, int sheet_height = 0)
            : base(Content.Load<Texture2D>(filename), tile_width, tile_height, sheet_width = 0, sheet_height = 0)
        {
            this.animating = animating;
        }

        //------------------- Functions

        // If we don't have an animation set up we can send in the data and it will do it for us
        public void AddAnimation(string name, int total_frames, int offset_x = 0, int offset_y = 0, int stop_frame = -1)
        {
            Animation animation = new Animation(total_frames, offset_x, offset_y, stop_frame);
            animations.Add(name, animation);
        }

        // If we have an animation made up already, we pass it and have it stored
        public void AddAnimation(string name, Animation animation)
        {
            animations.Add(name, animation);
        }

        // This sets our animation and whether it is animating or not
        public void SetAnimation(string name, bool animating = true)
        {
            if (!animations.ContainsKey(name))
                name = animations.First().Key;

            current_animation = name;

            this.animating = animating;
        }

        //------------------- Base functions

        public virtual void Update(GameTime gameTime)
        {
            if (animating)
            {
                timer += (float)gameTime.ElapsedGameTime.TotalSeconds;

                if (timer >= frame_time)
                {
                    timer = 0;

                    if (current_frame != animations[current_animation].totalFrames - 1)
                    {
                        current_frame++;
                    }
                    else if (repeating)
                    {
                        if (current_frame >= animations[current_animation].totalFrames - 1)
                        {
                            current_frame = 0;
                        }
                    }
                }
            }
            else if(animations[current_animation].StopFrame != -1)
            {
                current_frame = animations[current_animation].StopFrame;
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, null);

            int i = (animations[current_animation].OffsetY * sheet_width) + animations[current_animation].OffsetX + current_frame;

            spriteBatch.Draw(texture, position, regions[i], Color.White);

            spriteBatch.End();
        }

        // This disposes the instance of this class
        public new void Dispose()
        {
            this.Dispose();
            GC.SuppressFinalize(this);
        }
    }
}
